package com.shuda.business.user.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.shuda.business.user.entity.UserEntity;
import com.shuda.business.user.entity.RoleEntity;
import com.shuda.business.user.entity.MenuEntity;
import com.shuda.business.user.entity.PermissionEntity;
import com.shuda.business.user.mapper.UserMapper;
import com.shuda.business.user.mapper.RoleMapper;
import com.shuda.business.user.mapper.MenuMapper;
import com.shuda.business.user.mapper.PermissionMapper;
import com.shuda.business.user.mapper.UserRoleMapper;
import com.shuda.business.user.mapper.RolePermissionMapper;
import com.shuda.business.user.service.AuthService;
import com.shuda.common.dto.LoginDTO;
import com.shuda.common.dto.UserProfileDTO;
import com.shuda.common.dto.ChangePasswordDTO;
import com.shuda.common.security.SecurityUtils;
import com.shuda.common.security.JwtTokenProvider;
import com.shuda.common.result.Result;
import lombok.RequiredArgsConstructor;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 认证服务实现类
 */
@Service
@RequiredArgsConstructor
public class AuthServiceImpl implements AuthService {

    private final AuthenticationManager authenticationManager;
    private final JwtTokenProvider jwtTokenProvider;
    private final PasswordEncoder passwordEncoder;
    private final UserMapper userMapper;
    private final RoleMapper roleMapper;
    private final MenuMapper menuMapper;
    private final PermissionMapper permissionMapper;
    private final UserRoleMapper userRoleMapper;
    private final RolePermissionMapper rolePermissionMapper;

    @Override
    public Result<Map<String, Object>> login(LoginDTO loginDTO) {
        try {
            Authentication authentication = authenticationManager.authenticate(
                new UsernamePasswordAuthenticationToken(loginDTO.getUsername(), loginDTO.getPassword())
            );
            
            SecurityContextHolder.getContext().setAuthentication(authentication);
            
            String token = jwtTokenProvider.generateToken(authentication);
            String refreshToken = jwtTokenProvider.generateRefreshToken(authentication);
            
            UserEntity user = userMapper.selectOne(new LambdaQueryWrapper<UserEntity>()
                .eq(UserEntity::getUsername, loginDTO.getUsername()));
            
            Map<String, Object> result = new HashMap<>();
            result.put("token", token);
            result.put("refreshToken", refreshToken);
            result.put("userId", user.getId());
            result.put("username", user.getUsername());
            result.put("nickname", user.getNickname());
            result.put("avatar", user.getAvatar());
            result.put("tenantId", user.getTenantId());
            
            return Result.success(result);
        } catch (Exception e) {
            return Result.error("用户名或密码错误");
        }
    }

    @Override
    public Result<Boolean> logout() {
        SecurityContextHolder.clearContext();
        return Result.success(true);
    }

    @Override
    public Result<Map<String, Object>> refreshToken(String refreshToken) {
        if (jwtTokenProvider.validateToken(refreshToken)) {
            String username = jwtTokenProvider.getUsernameFromToken(refreshToken);
            UserEntity user = userMapper.selectOne(new LambdaQueryWrapper<UserEntity>()
                .eq(UserEntity::getUsername, username));
            
            if (user != null) {
                String newToken = jwtTokenProvider.generateTokenFromUsername(username);
                String newRefreshToken = jwtTokenProvider.generateRefreshTokenFromUsername(username);
                
                Map<String, Object> result = new HashMap<>();
                result.put("token", newToken);
                result.put("refreshToken", newRefreshToken);
                
                return Result.success(result);
            }
        }
        return Result.error("刷新令牌无效");
    }

    @Override
    public Result<UserEntity> getUserProfile() {
        Long userId = SecurityUtils.getCurrentUserId();
        UserEntity user = userMapper.selectById(userId);
        return Result.success(user);
    }

    @Override
    @Transactional
    public Result<Boolean> updateUserProfile(UserProfileDTO profileDTO) {
        Long userId = SecurityUtils.getCurrentUserId();
        UserEntity user = userMapper.selectById(userId);
        
        if (user == null) {
            return Result.error("用户不存在");
        }
        
        user.setNickname(profileDTO.getNickname());
        user.setEmail(profileDTO.getEmail());
        user.setPhone(profileDTO.getPhone());
        user.setAvatar(profileDTO.getAvatar());
        
        return Result.success(userMapper.updateById(user) > 0);
    }

    @Override
    @Transactional
    public Result<Boolean> changePassword(ChangePasswordDTO changePasswordDTO) {
        Long userId = SecurityUtils.getCurrentUserId();
        UserEntity user = userMapper.selectById(userId);
        
        if (user == null) {
            return Result.error("用户不存在");
        }
        
        if (!passwordEncoder.matches(changePasswordDTO.getOldPassword(), user.getPassword())) {
            return Result.error("原密码错误");
        }
        
        user.setPassword(passwordEncoder.encode(changePasswordDTO.getNewPassword()));
        return Result.success(userMapper.updateById(user) > 0);
    }

    @Override
    public Result<List<String>> getUserPermissions() {
        Long userId = SecurityUtils.getCurrentUserId();
        
        // 获取用户角色
        List<Long> roleIds = userRoleMapper.selectRoleIdsByUserId(userId);
        
        if (roleIds.isEmpty()) {
            return Result.success(new ArrayList<>());
        }
        
        // 获取角色权限
        List<Long> permissionIds = rolePermissionMapper.selectPermissionIdsByRoleIds(roleIds);
        
        if (permissionIds.isEmpty()) {
            return Result.success(new ArrayList<>());
        }
        
        // 获取权限编码
        List<PermissionEntity> permissions = permissionMapper.selectBatchIds(permissionIds);
        List<String> permissionCodes = permissions.stream()
            .map(PermissionEntity::getPermissionCode)
            .filter(Objects::nonNull)
            .distinct()
            .collect(Collectors.toList());
        
        return Result.success(permissionCodes);
    }

    @Override
    public Result<List<MenuEntity>> getUserMenus() {
        Long userId = SecurityUtils.getCurrentUserId();
        
        // 获取用户角色
        List<Long> roleIds = userRoleMapper.selectRoleIdsByUserId(userId);
        
        if (roleIds.isEmpty()) {
            return Result.success(new ArrayList<>());
        }
        
        // 获取角色权限
        List<Long> permissionIds = rolePermissionMapper.selectPermissionIdsByRoleIds(roleIds);
        
        if (permissionIds.isEmpty()) {
            return Result.success(new ArrayList<>());
        }
        
        // 获取权限对应的菜单
        List<Long> menuIds = permissionMapper.selectMenuIdsByPermissionIds(permissionIds);
        
        if (menuIds.isEmpty()) {
            return Result.success(new ArrayList<>());
        }
        
        // 获取菜单列表
        List<MenuEntity> menus = menuMapper.selectBatchIds(menuIds);
        
        // 构建菜单树
        List<MenuEntity> menuTree = buildMenuTree(menus);
        
        return Result.success(menuTree);
    }

    /**
     * 构建菜单树
     */
    private List<MenuEntity> buildMenuTree(List<MenuEntity> menus) {
        Map<Long, MenuEntity> menuMap = menus.stream()
            .collect(Collectors.toMap(MenuEntity::getId, menu -> menu));
        
        List<MenuEntity> rootMenus = new ArrayList<>();
        
        for (MenuEntity menu : menus) {
            if (menu.getParentId() == null || menu.getParentId() == 0) {
                rootMenus.add(menu);
            } else {
                MenuEntity parent = menuMap.get(menu.getParentId());
                if (parent != null) {
                    if (parent.getChildren() == null) {
                        parent.setChildren(new ArrayList<>());
                    }
                    parent.getChildren().add(menu);
                }
            }
        }
        
        return rootMenus.stream()
            .sorted(Comparator.comparing(MenuEntity::getSortOrder))
            .collect(Collectors.toList());
    }
}